package com.stu.jvm;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

/**
 * JVM类加载机制演示
 * 
 * 本类演示了Java类加载的完整过程，包括：
 * 1. 类加载器层次结构
 * 2. 双亲委派模型
 * 3. 类加载过程（加载、链接、初始化）
 * 4. 自定义类加载器
 * 5. 类加载时机
 * 6. 类初始化顺序
 * 
 * @author 学习者
 * @version 1.0
 * @since JDK 1.8
 */
public class ClassLoadingDemo {
    
    // 静态变量，用于演示类初始化顺序
    private static final String STATIC_FINAL_FIELD = "静态常量";
    private static String staticField = initStaticField();
    
    // 实例变量
    private String instanceField = initInstanceField();
    
    // 静态代码块
    static {
        System.out.println("ClassLoadingDemo 静态代码块执行");
    }
    
    // 实例代码块
    {
        System.out.println("ClassLoadingDemo 实例代码块执行");
    }
    
    /**
     * 主方法：演示类加载机制的各个方面
     */
    public static void main(String[] args) {
        System.out.println("=== JVM类加载机制演示 ===");
        
        // 1. 演示类加载器层次结构
        demonstrateClassLoaderHierarchy();
        
        // 2. 演示双亲委派模型
        demonstrateParentDelegationModel();
        
        // 3. 演示类加载过程
        demonstrateClassLoadingProcess();
        
        // 4. 演示类初始化时机
        demonstrateClassInitializationTiming();
        
        // 5. 演示类初始化顺序
        demonstrateInitializationOrder();
        
        // 6. 演示自定义类加载器
        demonstrateCustomClassLoader();
        
        // 7. 演示类加载的线程安全性
        demonstrateClassLoadingThreadSafety();
    }
    
    /**
     * 演示类加载器层次结构
     */
    private static void demonstrateClassLoaderHierarchy() {
        System.out.println("\n=== 类加载器层次结构 ===");
        
        // 获取当前类的类加载器
        ClassLoader currentClassLoader = ClassLoadingDemo.class.getClassLoader();
        System.out.println("当前类的类加载器：" + currentClassLoader);
        
        // 遍历类加载器层次结构
        ClassLoader loader = currentClassLoader;
        int level = 1;
        while (loader != null) {
            System.out.println("第" + level + "层：" + loader.getClass().getName());
            loader = loader.getParent();
            level++;
        }
        System.out.println("第" + level + "层：Bootstrap ClassLoader (C++实现，Java中为null)");
        
        System.out.println("\n类加载器说明：");
        System.out.println("1. Bootstrap ClassLoader：启动类加载器");
        System.out.println("   - 加载JDK核心类库（如java.lang.*）");
        System.out.println("   - 由C++实现，在Java中表现为null");
        System.out.println("   - 加载路径：$JAVA_HOME/jre/lib");
        
        System.out.println("\n2. Extension ClassLoader：扩展类加载器");
        System.out.println("   - 加载JDK扩展类库");
        System.out.println("   - 加载路径：$JAVA_HOME/jre/lib/ext");
        
        System.out.println("\n3. Application ClassLoader：应用程序类加载器");
        System.out.println("   - 加载用户类路径（classpath）上的类");
        System.out.println("   - 是大多数应用程序的默认类加载器");
        
        // 演示不同类的类加载器
        System.out.println("\n不同类的类加载器：");
        System.out.println("Object类：" + Object.class.getClassLoader()); // null，由Bootstrap加载
        System.out.println("String类：" + String.class.getClassLoader()); // null，由Bootstrap加载
        System.out.println("当前类：" + ClassLoadingDemo.class.getClassLoader()); // Application ClassLoader
    }
    
    /**
     * 演示双亲委派模型
     */
    private static void demonstrateParentDelegationModel() {
        System.out.println("\n=== 双亲委派模型 ===");
        
        System.out.println("双亲委派模型工作流程：");
        System.out.println("1. 当类加载器收到类加载请求时");
        System.out.println("2. 首先检查该类是否已经被加载");
        System.out.println("3. 如果没有加载，则委派给父类加载器");
        System.out.println("4. 父类加载器重复这个过程");
        System.out.println("5. 如果父类加载器无法加载，子类加载器才尝试加载");
        
        System.out.println("\n双亲委派模型的优点：");
        System.out.println("1. 避免类的重复加载");
        System.out.println("2. 保证Java核心API不被篡改");
        System.out.println("3. 提供了一种层次化的优先级关系");
        
        // 演示类加载的委派过程
        System.out.println("\n演示类加载委派：");
        try {
            // 尝试加载一个系统类
            Class<?> stringClass = Class.forName("java.lang.String");
            System.out.println("String类加载器：" + stringClass.getClassLoader());
            
            // 尝试加载一个应用类
            Class<?> currentClass = Class.forName("com.stu.jvm.ClassLoadingDemo");
            System.out.println("当前类加载器：" + currentClass.getClassLoader());
            
        } catch (ClassNotFoundException e) {
            System.err.println("类加载失败：" + e.getMessage());
        }
        
        System.out.println("\n破坏双亲委派模型的场景：");
        System.out.println("1. 线程上下文类加载器（TCCL）");
        System.out.println("2. OSGi模块化框架");
        System.out.println("3. 热部署和热替换");
        System.out.println("4. 自定义类加载器重写loadClass方法");
    }
    
    /**
     * 演示类加载过程
     */
    private static void demonstrateClassLoadingProcess() {
        System.out.println("\n=== 类加载过程 ===");
        
        System.out.println("类加载过程分为三个阶段：");
        
        System.out.println("\n1. 加载（Loading）：");
        System.out.println("   - 通过类的全限定名获取二进制字节流");
        System.out.println("   - 将字节流转换为方法区的运行时数据结构");
        System.out.println("   - 在内存中生成Class对象作为访问入口");
        
        System.out.println("\n2. 链接（Linking）：");
        System.out.println("   a) 验证（Verification）：");
        System.out.println("      - 文件格式验证：验证字节流符合Class文件格式");
        System.out.println("      - 元数据验证：验证字节码描述信息符合Java语言规范");
        System.out.println("      - 字节码验证：验证程序语义合法性");
        System.out.println("      - 符号引用验证：验证符号引用的正确性");
        
        System.out.println("\n   b) 准备（Preparation）：");
        System.out.println("      - 为类变量分配内存并设置初始值");
        System.out.println("      - 只包括static变量，不包括实例变量");
        System.out.println("      - 初始值是数据类型的零值，不是代码中的赋值");
        
        System.out.println("\n   c) 解析（Resolution）：");
        System.out.println("      - 将符号引用替换为直接引用");
        System.out.println("      - 包括类、接口、字段、方法的解析");
        
        System.out.println("\n3. 初始化（Initialization）：");
        System.out.println("   - 执行类构造器<clinit>()方法");
        System.out.println("   - 为类变量赋予正确的初始值");
        System.out.println("   - 执行静态代码块");
        System.out.println("   - 保证线程安全，同一时间只有一个线程执行");
        
        // 演示准备阶段和初始化阶段的区别
        System.out.println("\n准备阶段 vs 初始化阶段：");
        System.out.println("准备阶段：static int value = 123; // value = 0");
        System.out.println("初始化阶段：static int value = 123; // value = 123");
        System.out.println("特例：static final int value = 123; // 准备阶段就是123");
    }
    
    /**
     * 演示类初始化时机
     */
    private static void demonstrateClassInitializationTiming() {
        System.out.println("\n=== 类初始化时机 ===");
        
        System.out.println("主动引用（会触发初始化）：");
        System.out.println("1. 遇到new、getstatic、putstatic、invokestatic指令");
        System.out.println("2. 使用反射调用类");
        System.out.println("3. 初始化子类时，父类未初始化");
        System.out.println("4. 虚拟机启动时的主类");
        System.out.println("5. 使用动态语言支持时的方法句柄");
        
        System.out.println("\n被动引用（不会触发初始化）：");
        System.out.println("1. 通过子类引用父类静态字段");
        System.out.println("2. 通过数组定义引用类");
        System.out.println("3. 引用常量");
        
        // 演示被动引用
        System.out.println("\n演示被动引用：");
        
        // 1. 通过数组定义引用类（不会触发初始化）
        System.out.println("创建数组：");
        LazyInitClass[] array = new LazyInitClass[10];
        System.out.println("数组创建完成，LazyInitClass未初始化");
        
        // 2. 引用常量（不会触发初始化）
        System.out.println("\n引用常量：");
        System.out.println("常量值：" + LazyInitClass.CONSTANT);
        System.out.println("引用常量完成，LazyInitClass未初始化");
        
        // 3. 主动引用（会触发初始化）
        System.out.println("\n主动引用：");
        System.out.println("静态变量值：" + LazyInitClass.staticVar);
        System.out.println("主动引用完成，LazyInitClass已初始化");
    }
    
    /**
     * 演示类初始化顺序
     */
    private static void demonstrateInitializationOrder() {
        System.out.println("\n=== 类初始化顺序 ===");
        
        System.out.println("初始化顺序规则：");
        System.out.println("1. 父类静态变量和静态代码块（按声明顺序）");
        System.out.println("2. 子类静态变量和静态代码块（按声明顺序）");
        System.out.println("3. 父类实例变量和实例代码块（按声明顺序）");
        System.out.println("4. 父类构造方法");
        System.out.println("5. 子类实例变量和实例代码块（按声明顺序）");
        System.out.println("6. 子类构造方法");
        
        System.out.println("\n创建子类实例：");
        ChildClass child = new ChildClass();
        System.out.println("子类实例创建完成");
    }
    
    /**
     * 演示自定义类加载器
     */
    private static void demonstrateCustomClassLoader() {
        System.out.println("\n=== 自定义类加载器 ===");
        
        System.out.println("自定义类加载器的用途：");
        System.out.println("1. 加载非标准来源的类（网络、数据库等）");
        System.out.println("2. 实现类的热替换和热部署");
        System.out.println("3. 实现代码加密和解密");
        System.out.println("4. 实现类的隔离和沙箱");
        
        // 创建自定义类加载器实例
        CustomClassLoader customLoader = new CustomClassLoader();
        
        try {
            // 使用自定义类加载器加载类
            Class<?> clazz = customLoader.loadClass("java.lang.String");
            System.out.println("\n通过自定义类加载器加载String类：");
            System.out.println("类加载器：" + clazz.getClassLoader());
            System.out.println("说明：由于双亲委派，实际由Bootstrap ClassLoader加载");
            
        } catch (ClassNotFoundException e) {
            System.err.println("类加载失败：" + e.getMessage());
        }
        
        System.out.println("\n自定义类加载器实现要点：");
        System.out.println("1. 继承ClassLoader类");
        System.out.println("2. 重写findClass方法（推荐）或loadClass方法");
        System.out.println("3. 调用defineClass方法将字节码转换为Class对象");
        System.out.println("4. 处理类的依赖关系");
    }
    
    /**
     * 演示类加载的线程安全性
     */
    private static void demonstrateClassLoadingThreadSafety() {
        System.out.println("\n=== 类加载的线程安全性 ===");
        
        System.out.println("类加载的线程安全保证：");
        System.out.println("1. JVM保证类的初始化过程是线程安全的");
        System.out.println("2. 同一个类只会被初始化一次");
        System.out.println("3. 多线程同时加载同一个类时，只有一个线程执行初始化");
        System.out.println("4. 其他线程会等待初始化完成");
        
        // 演示多线程类加载
        System.out.println("\n演示多线程类加载：");
        
        for (int i = 0; i < 3; i++) {
            final int threadNum = i + 1;
            new Thread(() -> {
                System.out.println("线程" + threadNum + "开始加载ThreadSafeClass");
                // 触发类初始化
                ThreadSafeClass.getInstance();
                System.out.println("线程" + threadNum + "完成加载ThreadSafeClass");
            }).start();
        }
        
        // 等待线程执行完成
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        System.out.println("\n类加载死锁的可能性：");
        System.out.println("1. 两个类相互依赖且在不同线程中初始化");
        System.out.println("2. 自定义类加载器中的同步问题");
        System.out.println("3. 解决方案：避免循环依赖，合理设计类结构");
    }
    
    /**
     * 初始化静态字段
     */
    private static String initStaticField() {
        System.out.println("ClassLoadingDemo 静态字段初始化");
        return "静态字段";
    }
    
    /**
     * 初始化实例字段
     */
    private String initInstanceField() {
        System.out.println("ClassLoadingDemo 实例字段初始化");
        return "实例字段";
    }
    
    /**
     * 构造方法
     */
    public ClassLoadingDemo() {
        System.out.println("ClassLoadingDemo 构造方法执行");
    }
}

/**
 * 懒加载演示类
 */
class LazyInitClass {
    // 常量，在编译期就确定值，不会触发类初始化
    public static final String CONSTANT = "常量值";
    
    // 静态变量，会触发类初始化
    public static String staticVar = initStaticVar();
    
    static {
        System.out.println("LazyInitClass 静态代码块执行 - 类已初始化");
    }
    
    private static String initStaticVar() {
        System.out.println("LazyInitClass 静态变量初始化");
        return "静态变量值";
    }
}

/**
 * 父类，用于演示初始化顺序
 */
class ParentClass {
    // 静态变量
    private static String parentStaticField = initParentStaticField();
    
    // 实例变量
    private String parentInstanceField = initParentInstanceField();
    
    // 静态代码块
    static {
        System.out.println("ParentClass 静态代码块执行");
    }
    
    // 实例代码块
    {
        System.out.println("ParentClass 实例代码块执行");
    }
    
    public ParentClass() {
        System.out.println("ParentClass 构造方法执行");
    }
    
    private static String initParentStaticField() {
        System.out.println("ParentClass 静态字段初始化");
        return "父类静态字段";
    }
    
    private String initParentInstanceField() {
        System.out.println("ParentClass 实例字段初始化");
        return "父类实例字段";
    }
}

/**
 * 子类，用于演示初始化顺序
 */
class ChildClass extends ParentClass {
    // 静态变量
    private static String childStaticField = initChildStaticField();
    
    // 实例变量
    private String childInstanceField = initChildInstanceField();
    
    // 静态代码块
    static {
        System.out.println("ChildClass 静态代码块执行");
    }
    
    // 实例代码块
    {
        System.out.println("ChildClass 实例代码块执行");
    }
    
    public ChildClass() {
        System.out.println("ChildClass 构造方法执行");
    }
    
    private static String initChildStaticField() {
        System.out.println("ChildClass 静态字段初始化");
        return "子类静态字段";
    }
    
    private String initChildInstanceField() {
        System.out.println("ChildClass 实例字段初始化");
        return "子类实例字段";
    }
}

/**
 * 自定义类加载器
 */
class CustomClassLoader extends ClassLoader {
    
    public CustomClassLoader() {
        super(); // 使用系统类加载器作为父加载器
    }
    
    public CustomClassLoader(ClassLoader parent) {
        super(parent);
    }
    
    /**
     * 重写findClass方法，实现自定义加载逻辑
     */
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        System.out.println("CustomClassLoader.findClass: " + name);
        
        // 这里应该实现从自定义来源加载类的逻辑
        // 例如：从网络、数据库、加密文件等加载字节码
        
        // 为了演示，这里直接抛出异常
        throw new ClassNotFoundException("CustomClassLoader无法找到类: " + name);
    }
    
    /**
     * 可选：重写loadClass方法，破坏双亲委派模型
     * 注意：通常不建议重写此方法
     */
    /*
    @Override
    public Class<?> loadClass(String name) throws ClassNotFoundException {
        System.out.println("CustomClassLoader.loadClass: " + name);
        
        // 自定义加载逻辑，可以破坏双亲委派模型
        // 但要小心处理系统类，避免安全问题
        
        return super.loadClass(name);
    }
    */
    
    /**
     * 从字节数组定义类
     */
    public Class<?> defineClassFromBytes(String name, byte[] classBytes) {
        return defineClass(name, classBytes, 0, classBytes.length);
    }
}

/**
 * 线程安全的类加载演示
 */
class ThreadSafeClass {
    private static ThreadSafeClass instance;
    
    static {
        System.out.println("ThreadSafeClass 静态代码块开始执行 - 线程: " + 
                          Thread.currentThread().getName());
        
        // 模拟初始化耗时
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        instance = new ThreadSafeClass();
        System.out.println("ThreadSafeClass 静态代码块执行完成 - 线程: " + 
                          Thread.currentThread().getName());
    }
    
    public static ThreadSafeClass getInstance() {
        return instance;
    }
    
    private ThreadSafeClass() {
        System.out.println("ThreadSafeClass 构造方法执行 - 线程: " + 
                          Thread.currentThread().getName());
    }
}